///----------------------------------------------------------------------
///
/// EMC, Copyright (C) 2009 Carlos Abalde
///
/// This program is free software; you can redistribute it and/or
/// modify it under the terms of the GNU General Public License as
/// published by the Free Software Foundation; either version 2 of the
/// License, or (at your option) any later version.
///
/// This program is distributed in the hope that it will be useful,
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
/// General Public License for more details.
///
/// You should have received a copy of the GNU General Public License
/// along with this program; if not, write to the Free Software
/// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
/// 02111-1307 USA
///
///----------------------------------------------------------------------

#include <stdlib.h>
#include <unistd.h>
#include <string.h> 
#include "erlInterfaceUtils.h"

////////////////////////////////////////////////////////////////////////////////
int read_exact(byte *buf, int len)
////////////////////////////////////////////////////////////////////////////////
{
  int i, got=0;

  do
    {
      if ((i = read(0, buf+got, len-got)) <= 0)
	return(i);
      got += i;
    } while (got<len);

  return(len);
}

////////////////////////////////////////////////////////////////////////////////
int  write_exact(byte *buf, int len)
////////////////////////////////////////////////////////////////////////////////
{
  int i, wrote = 0;

  do
    {
      if ((i = write(1, buf+wrote, len-wrote)) <= 0)
	return (i);
      wrote += i;
    } while (wrote<len);

  return (len);
}

////////////////////////////////////////////////////////////////////////////////
byte *read_cmd()
////////////////////////////////////////////////////////////////////////////////
{
  int len;
  byte buffer[3], *resultBuffer;

  if (read_exact(buffer, 2) != 2)
    return NULL;

  len = (buffer[0] << 8) | buffer[1];

  resultBuffer = (byte *)malloc(sizeof(byte)*len);
  read_exact(resultBuffer, len);
  return resultBuffer;
}

////////////////////////////////////////////////////////////////////////////////
int write_cmd(byte *buf, int len)
////////////////////////////////////////////////////////////////////////////////
{
  byte li;

  li = (len >> 8) & 0xff;
  write_exact(&li, 1);

  li = len & 0xff;
  write_exact(&li, 1);

  return write_exact(buf, len);
}


////////////////////////////////////////////////////////////////////////////////
ETERM *reference2binary(void *reference)
////////////////////////////////////////////////////////////////////////////////
{
  int sizeOfReference = sizeof(void *);
  char direccion[sizeOfReference];
  memcpy(direccion, &reference, sizeOfReference);
  return erl_mk_binary(direccion, sizeOfReference);
}


////////////////////////////////////////////////////////////////////////////////
void *binary2reference(ETERM *binary)
////////////////////////////////////////////////////////////////////////////////
{
  void *reference;
  int sizeOfReference = sizeof(void *);
  char *direccion = (char *)ERL_BIN_PTR(binary);
  memcpy(&reference, direccion, sizeOfReference);
  return reference;
}

////////////////////////////////////////////////////////////////////////////////
void binary2bytes(ETERM *binary, byte *bytes[], unsigned int *nbytes)
////////////////////////////////////////////////////////////////////////////////
{
  *nbytes = ERL_BIN_SIZE(binary);
  *bytes = (byte *)malloc(sizeof(byte)*(*nbytes));
  byte *bytesPtr = (byte *)ERL_BIN_PTR(binary);
  memcpy(*bytes, bytesPtr, *nbytes);
}

////////////////////////////////////////////////////////////////////////////////
char* erl_iolist_to_string(const ETERM* term, int length)
////////////////////////////////////////////////////////////////////////////////
{
  ETERM* bin;
  if ((bin = erl_iolist_to_binary(term)) == NULL) {
    return NULL;
  } else {
    char* result = NULL;
    result = (char *) erl_malloc(length);
    memcpy(result, ERL_BIN_PTR(bin), length);
    erl_free_term(bin);
    return result;
  }
}
